﻿using Commission;
using Commission.Controllers;
using Commission.DAL;
using Commission.Helpers;
using Commission.Models;
using Commission.Resources;
using Commission.ViewModels;
using ExportToExcel;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace ContosoUniversity.Controllers
{
    public enum ActionMode
    {
        New = 1,
        Update = 2,
        Upgrade = 3,
    }; 

    [Authorize]
    public class CustomerController : BaseController
    {
        //private static SchoolContext context = new SchoolContext();
        private CustomerRepository db = new CustomerRepository(new SchoolContext());
        //private TransactionRepository tranDb = new TransactionRepository(new SchoolContext());

        // GET: Customer
        [Authorize]
        public ActionResult Index(string userName, int customerTypeId = 0)
        {
            List<Customer> customers = new List<Customer>();

            //db.GetCustomersWithAmount();

            Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());
            if (login == null)
            {
                ViewBag.CustomerTypeIDs = new SelectList(db.GetCustomerTypes(), "ID", "TypeName");
                return View(customers);
            }

            if (User.IsInRole("Admin"))
            {
                customers.AddRange(db.GetCustomers());
            }
            else
            {
                ViewBag.CustomerId = login.CustomerID;
                customers.AddRange(GetSubCustomers(login));
                customers.Insert(0, login);
            }

            if (!string.IsNullOrEmpty(userName))
            {
                customers = customers
                    .Where(s => s.UserName.ToUpper().Contains(userName.ToUpper())
                        || s.Name.ToUpper().Contains(userName.ToUpper())
                        )
                    .ToList();
            }

            if (customerTypeId != 0)
            {
                customers = customers
                    .Where(s => s.CustomerTypeID == customerTypeId)
                    .ToList();
            }
            
            if (login != null && login.CustomerType.IsOnline)
            {
                ViewBag.CanCreateDirect = true;
            }
            else
            {
                ViewBag.CanCreateDirect = false;
            }

            ViewBag.CustomerTypeIDs = new SelectList(db.GetCustomerTypes(), "ID", "TypeName");

            return View(customers);
        }

        public ActionResult ResetPassword(string userName)
        {
            ApplicationUserManager manager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
            ApplicationUser user = manager.FindByName(userName);

            manager.RemovePassword(user.Id);
            manager.AddPassword(user.Id, "123456");
            
            return RedirectToAction("Index");
        }

        private IdentityResult CreateUser(string userName)
        {
            ApplicationUserManager manager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();

            var user = manager.FindByName(userName);
            if (user != null)
            {
                return null;
            }

            user = new ApplicationUser { UserName = userName, Email = userName + "@gmail.com" };
            var result = manager.Create(user, userName);
            
            return result;
        }

        private IdentityResult DeleteUser(string userName)
        {
            var user = new ApplicationUser { UserName = userName, Email = userName + "@gmail.com" };
            ApplicationUserManager manager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
            var result = manager.Delete(user);
            return result;
        }

        private IList<Customer> GetSubCustomers(Customer customer)
        {
            if (customer.SubCustomers == null)
            {
                return null;
            }

            List<Customer> subCustomers = new List<Customer>();

            foreach (var subCustomer in customer.SubCustomers.OrderBy(c => c.UserName))
            {
                subCustomers.Add(subCustomer);

                subCustomers.AddRange(GetSubCustomers(subCustomer));
            }

            return subCustomers;
        }

        // GET: Customer/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Customer customer = db.GetCustomerByID(id);
            if (customer == null)
            {
                return HttpNotFound();
            }
            return View(customer);
        }

        // GET: Customer/Create
        [Authorize]
        public ActionResult Create(bool isDirectCustomer = false)
        {
            LoadDataForCombo(ActionMode.New);

            Customer customer = new Customer();
            //customer.UserName = Session.GetSessionValue<string>(Config.UserName);
            customer.UserName = CreateRandomUserName();
            customer.AttendantDate = DateTime.Now;
            if (isDirectCustomer)
            {
                Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());
                customer.DirectCustomerID = login.CustomerID;
            }

            CustomerProduct cp = new CustomerProduct()
            {
                Customer = customer,
                Products = db.GetProducts().ToList()
            };

            return View(cp);
        }

        public ActionResult Upgrade(int customerId, bool isDirectCustomer = false)
        {
            Customer customer = db.GetCustomerByID(customerId);
            customer.SponsorConfirmed = true;
            customer.ParentConfirmed = true;
            customer.OldCustomerTypeID = customer.CustomerTypeID;

            Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());
            if (isDirectCustomer)
            {
                customer.DirectCustomerID = login.CustomerID;

                if (!login.CustomerType.IsOnline)
                {
                    //return View(cp);
                    // TODO xuat loi
                }
            }

            LoadCustomerTypeComboForUpgrade(customer.CustomerType.AttendantFee);

            CustomerProduct cp = new CustomerProduct()
            {
                Customer = customer,
                Products = db.GetProducts().ToList()
            };

            return View(cp);
        }

        // POST: Customer/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(CustomerProduct customerProduct)
        {
            Customer customer = customerProduct.Customer;

            if (ModelState.IsValid)
            {
                if (CheckCustomer(customerProduct, ActionMode.New))
                {
                    Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());

                    var result = CreateUser(customer.UserName);

                    if (result == null || result.Succeeded)
                    {
                        try
                        {
                            if (db.InsertCustomer(customerProduct, login, ActionMode.New))
                            {
                                db.Save();
                            }
                            else
                            {
                                return View(customerProduct);
                            }
                        }
                        catch (Exception e)
                        {
                            //DeleteUser(customer.UserName);
                            ModelState.AddModelError("", e.Message);
                        }

                    }
                    else
                    {
                        ModelState.AddModelError("Customer.UserName", AppResource.ErrCanNotCreateCustomer);
                        return View(customerProduct);
                    }

                    return RedirectToAction("Index");
                }
            }

            LoadDataForCombo(ActionMode.New);

            return View(customerProduct);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Upgrade(CustomerProduct customerProduct)
        {
            Customer customer = customerProduct.Customer;

            if (ModelState.IsValid)
            {
                if (CheckCustomer(customerProduct, ActionMode.Upgrade))
                {
                    Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());

                    try
                    {
                        if (db.InsertCustomer(customerProduct, login, ActionMode.Upgrade))
                        {
                            db.Save();
                        }
                        else
                        {
                            return View(customerProduct);
                        }
                    }
                    catch (Exception e)
                    {
                        ModelState.AddModelError("", e.Message);
                    }

                    return RedirectToAction("Index");
                }
            }

            CustomerType customerType = db.GetCustomerTypeById(customer.OldCustomerTypeID);
            LoadCustomerTypeComboForUpgrade(customerType.AttendantFee);

            return View(customerProduct);
        }

        public ActionResult ConfirmPassword(int? id)
        {
            return PartialView(new LoginViewModel());
        }

        /*
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ConfirmPassword()
        {
            TempData["Msg"] = "Data has been saved succeessfully";

            return RedirectToAction("Index");
        }
         */

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ConfirmPassword(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            return View(model);
        }

        private const int MaxRow = 15;

        public ActionResult CustomerSearch(string term)
        {
            IEnumerable<Customer> customers = db.GetCustomers();
            string[] userNames = customers
                .Select(p => p.UserName)
                .Concat(customers.Select(p => p.Name))
                .ToArray();

            return this.Json(userNames
                .Where(t => t.ToUpper().Contains(term.ToUpper()))
                .Take(MaxRow), JsonRequestBehavior.AllowGet);
        }

        public ActionResult UserNameSearch(string term)
        {
            IEnumerable<Customer> customers = db.GetCustomers();
            string[] userNames = customers
                .Select(p => p.UserName)
                .ToArray();

            return this.Json(userNames
                .Where(t => t.ToUpper().Contains(term.ToUpper()))
                .Take(MaxRow), JsonRequestBehavior.AllowGet);
        }

        /**
         * Lấy danh sách hội viên chưa có đủ 2 chân
         */
        public ActionResult ParentCustomerSearch(string term, string extraParam = "")
        {
            Customer customer = db.GetCustomerByUserName(extraParam);
            string[] userNames = null;

            if (customer != null)
            {
                IEnumerable<Customer> customers = customer.GetChilds()
                    .Where(x => x.SubCustomers.Count < 2);
                userNames = customers
                    .Select(p => p.UserName)
                    .ToArray();
            }
            else
            {
                IEnumerable<Customer> customers = db.GetParentCustomers();
                userNames = customers
                    .Select(p => p.UserName)
                    .ToArray();
            }
            

            return this.Json(userNames
                .Where(t => t.ToUpper().Contains(term.ToUpper())), JsonRequestBehavior.AllowGet);
        }

        public ActionResult SubCustomerSearch(string term)
        {
            bool isAdmin = User.IsInRole("Admin");

            string[] userNames = null;

            if (isAdmin)
            {
                IEnumerable<Customer> customers = db.GetCustomers();
                userNames =
                    customers.Select(p => p.UserName)
                    .Concat(customers.Select(p => p.Name)).ToArray();
            }
            else
            {
                Customer customer = db.GetCustomerByUserName(User.Identity.GetUserName());

                if (customer != null)
                {
                    IList<Customer> customers = customer.AllSubCustomers();
                    customers.Insert(0, customer);

                    userNames =
                        customers.Select(p => p.UserName)
                        .Concat(customers.Select(p => p.Name)).ToArray();
                }
            }

            return this.Json(userNames
                .Where(t => t.ToUpper().Contains(term.ToUpper())), JsonRequestBehavior.AllowGet);
        }

        public ActionResult NameFromCode(string userName)
        {
            Customer customer = db.GetCustomerByUserName(userName);

            JsonResult json = this.Json(customer != null ? customer.Name : "", 
                JsonRequestBehavior.AllowGet);
            return json;
        }

        private string CreateRandomUserName()
        {
            string userName = db.GetMaxUserName();

            /*
            var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            var random = new Random();
            var result = new string(
                Enumerable.Repeat(chars, 6)
                          .Select(s => s[random.Next(s.Length)])
                          .ToArray());
            result = "HH38" + result;
             */

            return userName;
        }

        private bool CheckCustomer(CustomerProduct customerProduct, ActionMode mode)
        {
            Customer customer = customerProduct.Customer;

            if (!CheckUserName(customer, mode)) return false;
            if (!CheckSponsorCustomer(customer, mode)) return false;
            if (!CheckParentCustomer(customer, mode)) return false;
            
            CustomerType customerType = db.GetCustomerTypeById(customer.CustomerTypeID);

            decimal amount = decimal.Zero;
            bool chooseProduct = false;
            decimal productAmount = decimal.Zero;

            foreach (var product in customerProduct.Products)
            {
                if (product.Quantity > 0)
                {
                    chooseProduct = true;
                    productAmount += product.Quantity * product.Price;
                }
            }

            if (customerType.AttendantFee > 0) { 
                if (!chooseProduct)
                {
                    ModelState.AddModelError("Products",
                            AppResource.ErrorNotChooseProductYet);
                    return false;
                }
                else
                {
                    if (productAmount < customerType.AttendantFee)
                    {
                        ModelState.AddModelError("Products",
                            string.Format(
                            AppResource.ErrorNotEnoughProduct, customerType.FullTypeName));
                        return false;
                    }

                    // kiểm tra hội viên có đủ tiền để tạo hội viên tuyến dưới không
                    if (customer.DirectCustomerID != 0)
                    {
                        amount = db.GetTotalAmount80(customer.DirectCustomerID);

                        if (amount < productAmount)
                        {
                            ModelState.AddModelError("Customer.CustomerTypeID",
                                AppResource.ErrorNotEnoughMoneyToCreateCustomer);
                            return false;
                        }
                    }
                }
            }

            // set tạm vô đây để khi đăng ký online thì sẽ trừ tiền hội viên đăng ký online
            customer.Amount80 = productAmount;

            customer.UpgradeDate = customer.AttendantDate;
            customer.ValidDate = DateTime.Now.AddDays(customerType.ValidDays);

            return true;
        }

        private bool CheckUserName(Customer customer, ActionMode mode)
        {
            string prefix = "";
            if (mode == ActionMode.New || mode == ActionMode.Upgrade)
            {
                prefix = "Customer.";
            }

            if (customer.UserName.Length != 10)
            {
                ModelState.AddModelError(prefix + "UserName",
                        AppResource.ErrUserNameIsNotCorrect);
                return false;
            }

            if (!customer.UserName.StartsWith("HH38"))
            {
                ModelState.AddModelError(prefix + "UserName",
                        AppResource.ErrUserNameIsNotCorrect);
                return false;
            }

            if (mode == ActionMode.New)
            { 
                try
                {
                    string userName = customer.UserName.Substring(4);
                    decimal i = -1;
                    i = decimal.Parse(userName);

                    if (db.GetCustomerByUserName(customer.UserName) != null)
                    {
                        ModelState.AddModelError(prefix + "UserName",
                            AppResource.ErrUserNameIsExisted);
                        return false;
                    }
                }
                catch (Exception)
                {
                    ModelState.AddModelError(prefix + "UserName",
                            AppResource.ErrUserNameIsNotCorrect);
                    return false;
                }
            }

            if (mode == ActionMode.Upgrade && !customer.CustomerTypeConfirmed)
            {
                ModelState.AddModelError(prefix + "CustomerTypeID",
                    AppResource.ErrorCustomerTypeNotConfirmed);
                return false;
            }

            return true;
        }

        private bool CheckSponsorCustomer(Customer customer, ActionMode mode)
        {
            if (mode == ActionMode.Upgrade) return true;

            string prefix = "";
            if (mode == ActionMode.New)
            {
                prefix = "Customer.";
            }

            if (!string.IsNullOrEmpty(customer.SponsorUserName))
            {
                List<Customer> customers = db.GetCustomersByName(
                    customer.SponsorUserName).ToList<Customer>();

                if (customers.Count == 0)
                {
                    ModelState.AddModelError(prefix + "SponsorUserName",
                        AppResource.ErrNotExistCustomer);
                    return false;
                }
                /* Vì hiện tại chỉ cho nhập mã nên ko tồn tại trường hợp bị trùng
                else if (customers.Count > 1)
                {
                    ModelState.AddModelError(prefix + "SponsorUserName",
                        AppResource.ErrDuplicateCustomer);
                    return false;
                }
                */

                if (mode == ActionMode.New && !customer.SponsorConfirmed)
                {
                    ModelState.AddModelError(prefix + "SponsorUserName",
                        AppResource.ErrSponsorNotConfirmed);
                    return false;
                }

                customer.SponsorCustomerID = customers[0].CustomerID;
            }
            else if (!string.IsNullOrEmpty(customer.ParentUserName))
            {
                // TODO bắt buộc nhập sponsor
                ModelState.AddModelError(prefix + "SponsorUserName",
                    AppResource.ErrNotExistCustomer);
                return false;
            }

            return true;
        }

        private bool CheckParentCustomer(Customer customer, ActionMode mode)
        {
            if (mode == ActionMode.Upgrade) return true;

            string prefix = "";
            if (mode == ActionMode.New)
            {
                prefix = "Customer.";
            }

            if (!string.IsNullOrEmpty(customer.ParentUserName))
            {
                List<Customer> customers = db.GetCustomersByName(
                    customer.ParentUserName).ToList<Customer>();

                if (customers.Count == 0)
                {
                    ModelState.AddModelError(prefix + "ParentUserName",
                        AppResource.ErrNotExistCustomer);
                    return false;
                }
                else if (customers.Count > 1)
                {
                    ModelState.AddModelError(prefix + "ParentUserName",
                        AppResource.ErrDuplicateCustomer);
                    return false;
                }

                if (mode == ActionMode.New && !customer.ParentConfirmed)
                {
                    ModelState.AddModelError(prefix + "ParentUserName",
                        AppResource.ErrParentNotConfirmed);
                    return false;
                }

                customer.ParentCustomerID = customers[0].CustomerID;
            }

            if (customer.ParentCustomerID != null)
            {
                Customer parentCustomer = db.GetCustomerByID(customer.ParentCustomerID);
                Customer sponsorCustomer = db.GetCustomerByID(customer.SponsorCustomerID);

                if (sponsorCustomer != null)
                {
                    IEnumerable<Customer> customers = sponsorCustomer.GetChilds()
                        .Where(x => x.SubCustomers.Count < 2);
                    if (!customers.Contains(parentCustomer))
                    {
                        ModelState.AddModelError(prefix + "ParentUserName",
                            AppResource.ErrorParentNotBelongToSponsor);
                        return false;
                    }
                }

                int count = parentCustomer.SubCustomers.Count;
                if (count >= 2)
                {
                    ModelState.AddModelError(prefix + "ParentUserName",
                        AppResource.ErrParentCustomerHave2Legs);
                    return false;
                }
                customer.Position = count + 1;
            }

            return true;
        }

        private void LoadDataForCombo(ActionMode mode)
        {
            /*
            var positions = new List<SelectListItem>
            {
                new SelectListItem { Text = "Trái", Value = "1" },
                new SelectListItem { Text = "Phải", Value = "2" },
            };
            ViewBag.Position = positions;
             */
            ViewBag.CustomerTypeIDs = new SelectList(
                db.GetCustomerTypes(), "ID", "TypeName");
        }

        private void LoadCustomerTypeComboForUpgrade(decimal amount)
        {
            ViewBag.CustomerTypeIDs = new SelectList(
                db.GetCustomerTypes().Where(x => IsUpgradeType(x, amount))
                , "ID", "TypeName");
        }

        private bool IsUpgradeType(CustomerType customerType, decimal amount)
        {
            if ((customerType.ID == (int)CustomerKind.NP
                || customerType.ID == (int)CustomerKind.VP
                || customerType.ID == (int)CustomerKind.AP)
                && customerType.AttendantFee > amount)
            {
                return true;
            }

            return false;
        }

        // GET: Customer/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Customer customer = db.GetCustomerByID(id);
            if (customer == null)
            {
                return HttpNotFound();
            }
            ViewBag.CustomerTypeIDs = new SelectList(db.GetCustomerTypes(), "ID", "TypeName", customer.CustomerTypeID);
            customer.OldCustomerTypeID = customer.CustomerTypeID;

            return View(customer);
        }

        // POST: Customer/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "CustomerID,Name,BirthDay,IDCard,PhoneNumber,Address,AttendantDate,UpgradeDate,ValidDate,CustomerTypeID,OldCustomerTypeID,ParentCustomerID,ParentUserName,SponsorCustomerID,SponsorUserName,UserName,DirectCustomerID,Gender")] Customer customer)
        {
            if (ModelState.IsValid)
            {
                if (CheckUpdateCustomer(customer)) {
                    db.UpdateCustomer(customer);
                    db.Save();
                    return RedirectToAction("Index");
                }
            }
            ViewBag.CustomerTypeID = new SelectList(db.GetCustomerTypes(), "ID", "TypeName", customer.CustomerTypeID);
            return View(customer);
        }

        private bool CheckUpdateCustomer(Customer customer)
        {
            return true;
            if (!CheckSponsorCustomer(customer, ActionMode.Update)) return false;
            if (!CheckParentCustomer(customer, ActionMode.Update)) return false;

            // từ đây trở xuống là kiểm tra có thay đổi customertype ko
            if (customer.OldCustomerTypeID == customer.CustomerTypeID) return true;

            CustomerType oldCustomerType = db.GetCustomerTypeById(customer.OldCustomerTypeID);
            CustomerType customerType = db.GetCustomerTypeById(customer.CustomerTypeID);

            // không thể upgrade từ gói cao về gói thấp
            if (customerType.MaxDailyProfit < oldCustomerType.MaxDailyProfit)
            {
                ModelState.AddModelError("CustomerTypeID", 
                    string.Format(AppResource.ErrorCannotUpgradeFromTo, 
                    oldCustomerType.FullTypeName, customerType.FullTypeName));
                return false;
            }
            
            SponsorCommission commission = db.GetSponsorCommission(
                customer.OldCustomerTypeID, customer.CustomerTypeID);
            DateTime date = customer.UpgradeDate.AddDays(commission.UpgradeDays);
            if (date.CompareTo(DateTime.Now) < 1)
            {
                ModelState.AddModelError("CustomerTypeID",
                    string.Format(AppResource.ErrorCannotUpgradeTo, customerType.FullTypeName));
                return false;
            }

            customer.UpgradeDate = DateTime.Now;
            customer.ValidDate = customer.UpgradeDate.AddDays(customerType.ValidDays);

            return true;
        }

        // GET: Customer/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Customer customer = db.GetCustomerByID(id);
            if (customer == null)
            {
                return HttpNotFound();
            }
            return View(customer);
        }

        /**
         * Cân chân
         *
         */ 
        public ActionResult GetPoint(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            if (id == 0) {
                IEnumerable<Customer> customers = db.GetCustomers();

                foreach (var customer in customers)
                {
                    GetPointForCustomer(customer);
                }
            }
            else
            {
                Customer customer = db.GetCustomerByID(id);
                if (customer == null)
                {
                    return HttpNotFound();
                }
                GetPointForCustomer(customer);
            }

            return RedirectToAction("Index", "Transaction");
        }

        private void GetPointForCustomer(Customer customer)
        {
            int adminId = 99999;

            // điểm trái, phải trên cây hội viên
            decimal leftPoint = customer.GetPoint(1);
            decimal rightPoint = customer.GetPoint(2);

            // điểm trái, phải trong db
            decimal leftPointInDb = db.GetTotalLeftPoint(customer.CustomerID);
            decimal rightPointInDb = db.GetTotalRightPoint(customer.CustomerID);
            decimal totalPoint = db.GetTotalHistoryPoint(customer.CustomerID);

            leftPoint = leftPoint - totalPoint - leftPointInDb;
            rightPoint = rightPoint - totalPoint - rightPointInDb;
            
            Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());
            DateTime now = DateTime.Now;

            // trường hợp hội viên hết hạn thì hủy bỏ số điểm còn lại
            if (DateTime.Now.CompareTo(customer.ValidDate) > 0)
            {
                TransactionHistory history = new TransactionHistory()
                {
                    CustomerID = customer.CustomerID,
                    AccountType = AccountType.MinusPoint,
                    AccountDate = DateTime.Now,
                    Point = 0,
                    Amount = 0,
                    ProductAmount = 0,
                    Description = AppResource.MessageDeletePoint,
                    CreatedUserId = login != null ? login.CustomerID : adminId,
                    CreatedAt = now,
                    UpdatedUserId = login != null ? login.CustomerID : adminId,
                    UpdatedAt = now,
                };
                 
                if (leftPoint < rightPoint)
                {
                    history.RightPoint = rightPoint - leftPoint;
                    history.Point = leftPoint;
                }
                else
                {
                    history.LeftPoint = leftPoint - rightPoint;
                    history.Point = rightPoint;
                }
                db.InsertTransactionHistory(history);
                db.Save();

                return;
            }
            
            decimal amount = 0;

            decimal point = leftPoint < rightPoint ? leftPoint : rightPoint;

            if (rightPoint > 0 && leftPoint > 0)
            {
                foreach (var pointCommission in customer.CustomerType.PointCommissions)
                {
                    if (point >= pointCommission.MinPoint)
                    {
                        if (point >= pointCommission.MaxPoint)
                        {
                            amount += pointCommission.MaxPoint * pointCommission.Amount;
                        }
                        else
                        {
                            amount += (point - pointCommission.MinPoint + 1)
                                    * pointCommission.Amount;
                        }
                    }
                }

                TransactionHistory history = new TransactionHistory()
                {
                    CustomerID = customer.CustomerID,
                    AccountType = AccountType.Pairing,
                    AccountDate = DateTime.Now,
                    Point = point,
                    Amount = amount * new decimal(0.8),
                    ProductAmount = amount * new decimal(0.2),
                    Description = AppResource.MessagePointCommission,
                    CreatedUserId = login != null ? login.CustomerID : adminId,
                    CreatedAt = now,
                    UpdatedUserId = login != null ? login.CustomerID : adminId,
                    UpdatedAt = now,
                };
                db.InsertTransactionHistory(history);
                db.Save();
            }
        }

        public ActionResult ExportToExcel()
        {
            CreateExcelFile.CreateExcelDocument(db.GetCustomers().ToList(), 
                "hoivien.xlsx", HttpContext.ApplicationInstance.Response);

            return View();
        }

        [Authorize]
        public ActionResult Information()
        {
            SetHome();

            return View(new CustomerInformation());
        }

        [Authorize]
        public ActionResult Active(CustomerInformation info)
        {
            Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());
            SetHome();

            int activeType = 0;
            string description = "";
            decimal activeAmount = 700000;

            Customer customer = null;
            if (!string.IsNullOrEmpty(info.UserName))
            {
                customer = db.GetCustomerByUserName(info.UserName);

                if (customer == null)
                {
                    ModelState.AddModelError("UserName", AppResource.ErrNotExistCustomer);
                    return View("Information", info);
                }
            }

            if (User.IsInRole("Admin"))
            {
                if (customer == null)
                {
                    ModelState.AddModelError("UserName", AppResource.ErrorActiveUserNameRequired);
                    return View("Information", info);
                }

                description = AppResource.MessageAdminActive;
                activeType = 1;
            }
            else
            {
                decimal amount = db.GetTotalAmount20(login.CustomerID);
                if (amount < activeAmount)
                {
                    ModelState.AddModelError("UserName", AppResource.ErrorActiveNotEnoughAmount);
                    return View("Information", info);
                }

                if (customer != null && customer.CustomerID != login.CustomerID)
                {
                    description = AppResource.LabelActiveForOther;
                    activeType = 2;
                } else {
                    description = AppResource.LabelActive;
                    activeType = 3;
                }
            }

            DateTime now = DateTime.Now;

            // trừ tiền năng động
            TransactionHistory history = new TransactionHistory()
            {
                AccountType = AccountType.Active,
                AccountDate = DateTime.Now,
                Point = 0,
                ProductAmount = 0,
                Description = description,
                CreatedUserId = login.CustomerID,
                CreatedAt = now,
                UpdatedUserId = login.CustomerID,
                UpdatedAt = now,
            };

            List<TransactionHistory> trans = new List<TransactionHistory>();

            if (activeType == 1) 
            {
                history.CustomerID = login.CustomerID;
                history.SponsoredCustomerID = customer.CustomerID;
                history.ProductAmount = 0;

                customer.ValidDate = DateTime.Now.AddDays(customer.CustomerType.ValidDays);
                db.UpdateCustomer(customer);

                Calculate(login, customer.CustomerID, customer.SponsorCustomer, 1, trans);
            }
            else if (activeType == 2)
             {
                history.CustomerID = login.CustomerID;
                history.SponsoredCustomerID = customer.CustomerID;
                history.ProductAmount = -activeAmount;

                customer.ValidDate = DateTime.Now.AddDays(customer.CustomerType.ValidDays);
                db.UpdateCustomer(customer);

                Calculate(login, customer.CustomerID, customer.SponsorCustomer, 1, trans);
            }
            else if (activeType == 3)
            {
                history.CustomerID = login.CustomerID;
                history.ProductAmount = -activeAmount;

                login.ValidDate = DateTime.Now.AddDays(login.CustomerType.ValidDays);
                db.UpdateCustomer(login);

                Calculate(login, login.CustomerID, login.SponsorCustomer, 1, trans);
            }

            db.InsertTransactionHistory(history);

            for (int i = 0; i < trans.Count; i++)
            {
                history = trans[i];
                int sponsorNumbers = history.SponsorNumbers;
                decimal amount = 0;

                for (int j = 0; j < i; j++)
                {
                    TransactionHistory prevHistory = trans[j];
                    int diffLevel = i - j;

                    if (diffLevel > 0) {
                        if ((sponsorNumbers == 1 && diffLevel <= 2)
                            || (sponsorNumbers == 2 && diffLevel <= 4)
                            || (sponsorNumbers == 3 && diffLevel <= 6)
                            || (sponsorNumbers == 4 && diffLevel <= 8)
                            || (sponsorNumbers >= 5 && diffLevel <= 10)
                            )
                        {
                            UniLevel uniLevel = db.GetUniLevel(diffLevel);
                            amount =  uniLevel.MatchingPercent * prevHistory.TotalAmount / 100;
                            history.Amount += amount * new decimal(0.8);
                            history.ProductAmount += amount * new decimal(0.2);
                        }
                    }
                }

                // check số tiền hoa hồng đã nhận trong ngày
                decimal remainAmount = db.GetRemainAmount(history.CustomerID);
                if (remainAmount > 0) {
                    if (remainAmount < history.TotalAmount)
                    {
                        history.Amount = remainAmount * new decimal(0.8);
                        history.ProductAmount = remainAmount * new decimal(0.2);
                    }

                    db.InsertTransactionHistory(history);
                }
            }

            db.Save();

            return RedirectToAction("Information");
        }

        // customerId là hội viên được năng động
        // cubCustomer số tiền hoa hồng nhận được của khách hàng ở dưới
        private void Calculate(Customer login, int customerId, Customer customer, int level,
                List<TransactionHistory> maps) {
            if (customer == null) return;

            int sponsorNumbers = CountSponsoredCustomer(customer);

            DateTime now = DateTime.Now;
            decimal amount = 0;

            if ((sponsorNumbers == 1 && level <= 2)
                || (sponsorNumbers == 2 && level <= 4)
                || (sponsorNumbers == 3 && level <= 6)
                || (sponsorNumbers == 4 && level <= 8)
                || (sponsorNumbers >= 5 && level <= 10)
                )
            {
                UniLevel uniLevel = db.GetUniLevel(level);
                amount =  uniLevel.Percent * 30 * Const.Rate / 100;
            }

            if (amount > 0)
            {
                TransactionHistory history = new TransactionHistory()
                {
                    CustomerID = customer.CustomerID,
                    SponsoredCustomerID = customerId,
                    AccountType = AccountType.Matching,
                    AccountDate = DateTime.Now,
                    Point = 0,
                    Amount = amount * new decimal(0.8),
                    ProductAmount = amount * new decimal(0.2),
                    Description = AppResource.MessageActiveCommmision,
                    SponsorNumbers = sponsorNumbers,
                    CurrentLevel = level,
                    CreatedUserId = login.CustomerID,
                    CreatedAt = now,
                    UpdatedUserId = login.CustomerID,
                    UpdatedAt = now,
                };

                maps.Add(history);
            }

            Calculate(login, customerId, customer.SponsorCustomer, level + 1, maps);
        }

        private int CountSponsoredCustomer(Customer customer)
        {
            IList<Customer> leftCustomers = customer.GetChilds(1);
            IList<Customer> rightCustomers = customer.GetChilds(2);

            int left = 0;
            int right = 0;

            foreach (var subCustomer in customer.SponsoredCustomers)
            {
                if (leftCustomers.Contains(subCustomer))
                {
                    left++;
                }
                else
                {
                    right++;
                }
            }

            return left > right ? right : left;
        }

        

        private void SetHome()
        {
            Customer login = db.GetCustomerByUserName(User.Identity.GetUserName());
            List<SponsorCommission> commissions = db.GetSponsorCommission(login.CustomerTypeID);

            DateTime startTime = DateTime.Now;
            DateTime endTime = login.ValidDate;
            TimeSpan span = endTime - startTime;

            if (commissions.Count > 0)
            {
                endTime = login.UpgradeDate.AddDays(commissions[0].UpgradeDays);

                if (startTime.CompareTo(endTime) < 0)
                {
                    span = endTime - startTime;
                    ViewBag.UpgradeTime1 = span.Days.ToString("D2")
                        + " " + span.Hours.ToString("D2")
                        + " " + span.Minutes.ToString("D2")
                        + " " + span.Seconds.ToString("D2");
                }
                else
                {
                    ViewBag.UpgradeTime1 = "00 00 00 00 ";
                }
                ViewBag.Package1Title = commissions[0].CustomerType.FullTypeName;

                if (commissions.Count > 1)
                {
                    endTime = login.UpgradeDate.AddDays(commissions[1].UpgradeDays);

                    if (startTime.CompareTo(endTime) < 0)
                    {
                        span = endTime - startTime;
                        ViewBag.UpgradeTime2 = span.Days.ToString("D2")
                            + " " + span.Hours.ToString("D2")
                            + " " + span.Minutes.ToString("D2")
                            + " " + span.Seconds.ToString("D2");
                        ViewBag.Package2Title = commissions[1].CustomerType.FullTypeName;
                    }
                }
            }

            endTime = login.ValidDate;
            if (startTime.CompareTo(endTime) < 0)
            {
                span = endTime.Subtract(startTime);
                ViewBag.ValidTime = span.Days.ToString("D2")
                    + " " + span.Hours.ToString("D2")
                    + " " + span.Minutes.ToString("D2")
                    + " " + span.Seconds.ToString("D2");
            }
        }

        // POST: Customer/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            //Customer customer = db.GetCustomerByID(id);
            db.DeleteTransactionByCustomerId(id);
            
            db.DeleteCustomer(id);

            db.Save();

            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
